using System;
using System.Collections.Generic;
using System.Linq;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Audio;
using Microsoft.Xna.Framework.Content;
using Microsoft.Xna.Framework.GamerServices;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Input;
using Microsoft.Xna.Framework.Media;

namespace Batty
{
    /// <summary>
    /// This is the main type for your game
    /// </summary>
    public class Pondhawk : Microsoft.Xna.Framework.Game
    {
        GraphicsDeviceManager graphics;
        SpriteBatch spriteBatch;

        public Model ground;
        private Camera camera;
        public Model digger;
        public float moreRats=0; 
        //public Field field;
        // public Lego lego;
        BattyScreen playscreen = null;
        SplashGameScreen splashScreen = null;
        ScoreScreen scoreScreen = null;
        GameScreen screen = null;
        public enum GameScreens { Splash, Batty, Score };

        //Will

        private Cue sqeek = null;
        /// <summary>
        /// A reference to the audio engine we use
        /// </summary>
        AudioEngine audioEngine;

        /// <summary>
        /// The loaded audio wave bank
        /// </summary>
        WaveBank waveBank;

        /// <summary>
        /// The loaded audio sound bank
        /// </summary>
        SoundBank soundBank;


        public KeyboardState lastKeyboardState;

        public Camera Camera { get { return camera; } }
        public SoundBank SoundBank { get { return soundBank; } }
        public GraphicsDeviceManager Graphics { get { return graphics; } }


        public Pondhawk()
        {
            graphics = new GraphicsDeviceManager(this);
            Content.RootDirectory = "Content";

            playscreen = new BattyScreen(this);
            splashScreen = new SplashGameScreen(this);
            scoreScreen = new ScoreScreen(this);
            screen = splashScreen;


            //Will


            camera = new Camera(graphics);
            camera.UseChaseCamera = true;
        }

        public void SetScreen(GameScreens newScreen)
        {
            screen.Deactivate();
            switch (newScreen)
            {
                case GameScreens.Splash:
                    screen = splashScreen;
                    break;

                case GameScreens.Batty:
                    screen = playscreen;
                    break;
                case GameScreens.Score:
                    screen = scoreScreen;
                    break;
            }
            screen.Activate();
        }
        /// <summary>
        /// Allows the game to perform any initialization it needs to before starting to run.
        /// This is where it can query for any required services and load any non-graphic
        /// related content.  Calling base.Initialize will enumerate through any components
        /// and initialize them as well.
        /// </summary>
        protected override void Initialize()
        {
            // TODO: Add your initialization logic here
            camera.Initialize();
            camera.Eye = new Vector3(10, 10, 10);

            lastKeyboardState = Keyboard.GetState();

            base.Initialize();
            playscreen.Initialize();
            splashScreen.Initialize();
        }

        /// <summary>
        /// LoadContent will be called once per game and is the place to load
        /// all of your content.
        /// </summary>
        protected override void LoadContent()
        {

            audioEngine = new AudioEngine("Content\\PondhawkAudio.xgs");
            waveBank = new WaveBank(audioEngine, "Content\\Wave Bank.xwb");
            soundBank = new SoundBank(audioEngine, "Content\\Sound Bank.xsb");


            // Create a new SpriteBatch, which can be used to draw textures.
            playscreen.LoadContent();
            splashScreen.LoadContent();
            scoreScreen.LoadContent();
            screen.Activate();
            spriteBatch = new SpriteBatch(GraphicsDevice);
            playscreen.rats.LoadContent(Content);
            playscreen.field.LoadContent(Content);
            playscreen.lego.LoadContent(Content);
            playscreen.bat.LoadContent(Content);
            // digger = Content.Load<Model>("Lego");




            // TODO: use this.Content to load your game content here
        }

        /// <summary>
        /// UnloadContent will be called once per game and is the place to unload
        /// all content.
        /// </summary>
        protected override void UnloadContent()
        {
            // TODO: Unload any non ContentManager content here
        }

        /// <summary>
        /// Allows the game to run logic such as updating the world,
        /// checking for collisions, gathering input, and playing audio.
        /// </summary>
        /// <param name="gameTime">Provides a snapshot of timing values.</param>
        protected override void Update(GameTime gameTime)
        {
            // Allows the game to exit
            if (GamePad.GetState(PlayerIndex.One).Buttons.Back == ButtonState.Pressed)
                this.Exit();
            //  screen.Update(gameTime);
            camera.Update(gameTime);


            // Update audioEngine.
            audioEngine.Update();


            // TODO: Add your update logic here
            playscreen.rats.Update(gameTime);

            int i = playscreen.rats.rats.Count(); ;
            System.Diagnostics.Trace.WriteLine("Rats Count:" + i.ToString());
            for (int j = i; i > 0; i--)
            {
                playscreen.rats.testRatsForCollision(playscreen.rats.rats.Last());
                playscreen.rats.rats.RemoveLast();
            }
            //  System.Diagnostics.Trace.WriteLine("Rats Count:" + rats.ratsCopy.Count().ToString());
            for (int j = playscreen.rats.ratsCopy.Count(); j > 0; j--)
            {
                playscreen.rats.rats.AddLast(playscreen.rats.ratsCopy.Last());
                playscreen.rats.ratsCopy.RemoveLast();
            }

            playscreen.rats.ratsCopy.Clear();
            // rats.finishCollision();
            moreRats += (float)gameTime.ElapsedGameTime.TotalSeconds;
            if (moreRats >= 1)
            {
                playscreen.rats.addRat(Content);
                moreRats = 0;
            }
            foreach (LaserFire.LaserBlast blast in playscreen.bat.LaserFire.LaserBlasts)
            {

                playscreen.rats.testEchoForCollision(blast.position);
            }

            

            // Game end condition
            if (playscreen.rats.checkLost(playscreen.lego.getSphere()) == true)
            {
                System.Diagnostics.Trace.WriteLine("GOTOSCORESCREEN");
                this.SetScreen(GameScreens.Score);
            }



            //Will
            KeyboardState keyboardState = Keyboard.GetState();

            if ((keyboardState.IsKeyDown(Keys.X) && lastKeyboardState.IsKeyUp(Keys.X)))
            {
                playscreen.bat.Flapping = !playscreen.bat.Flapping;
            }
            lastKeyboardState = keyboardState;

            if ((keyboardState.IsKeyDown(Keys.Space) && lastKeyboardState.IsKeyUp(Keys.X)))
            {

            }


            if (keyboardState.IsKeyDown(Keys.E))
            {
                playscreen.bat.Flap = 1;
                playscreen.bat.Flapping = true;
                if (sqeek == null)
                {
                    sqeek = this.SoundBank.GetCue("bat1");
                    sqeek.Play();
                }

                else if (sqeek.IsPaused)
                {
                    sqeek.Resume();
                }
            }
            else
            {
                playscreen.bat.Flap = 0;
                playscreen.bat.Flapping = false;
                if (sqeek != null && sqeek.IsPlaying)
                {
                    sqeek.Pause();
                }
            }

            if (keyboardState.IsKeyDown(Keys.Left))
            {
                playscreen.bat.TurnRate = 1f;
                playscreen.bat.BankRate = -.5f;

            }
            else if (keyboardState.IsKeyDown(Keys.Right))
            {
                playscreen.bat.TurnRate = -1f;
                playscreen.bat.BankRate = .5f;

            }
            else
            {
                playscreen.bat.TurnRate = 0;
                playscreen.bat.BankRate = 0;
            }

            if (keyboardState.IsKeyDown(Keys.Up))
            {
                playscreen.bat.ElevRate = 0.75f;
            }
            else if (keyboardState.IsKeyDown(Keys.Down))
            {
                playscreen.bat.ElevRate = -0.75f;
            }
            else
            {
                playscreen.bat.ElevRate = 0;
            }

            if (keyboardState.IsKeyDown(Keys.Space))
            {

                playscreen.bat.FireLaser();

            }
            if (keyboardState.IsKeyDown(Keys.Enter))
            {
                this.SetScreen(GameScreens.Batty);
            }
            lastKeyboardState = keyboardState;


            Matrix[] transforms = new Matrix[playscreen.bat.Model.Bones.Count];
            playscreen.bat.Model.CopyAbsoluteBoneTransformsTo(transforms);
            Matrix batTransform = playscreen.bat.Transform;

            foreach (ModelMesh mesh in playscreen.bat.Model.Meshes)
            {
                BoundingSphere bs = mesh.BoundingSphere;
                bs = bs.Transform(transforms[mesh.ParentBone.Index] * batTransform);
                if (false)
                {

                    this.Initialize();

                }
            }

            playscreen.bat.Update(gameTime);

            playscreen.rats.checkConfusionState((float)gameTime.ElapsedGameTime.TotalSeconds);
            camera.UseChaseCamera = true;
            camera.DesiredEye = Vector3.Transform(new Vector3(0, 50, -50), playscreen.bat.Transform);
            camera.Center = playscreen.bat.Position;
            camera.Up = playscreen.bat.Transform.Up;





            base.Update(gameTime);
        }

        /// <summary>
        /// This is called when the game should draw itself.
        /// </summary>
        /// <param name="gameTime">Provides a snapshot of timing values.</param>
        protected override void Draw(GameTime gameTime)
        {
            GraphicsDevice.Clear(Color.Black);
            screen.Draw(gameTime);
            spriteBatch.Begin(SpriteSortMode.BackToFront, BlendState.AlphaBlend);
            screen.DrawSprites(gameTime, spriteBatch);//more sprite code 12

            spriteBatch.End();
            // TODO: Add your drawing code here
            //  rats.Draw(graphics, gameTime, this);
            // DrawModel(ground, Matrix.Identity);
            //  DrawModel(digger, Matrix.Identity);

            //Will
            //  bat.Draw(graphics, gameTime);

            base.Draw(gameTime);
        }


        private void DrawModel(Model model, Matrix world)
        {
            Matrix[] transforms = new Matrix[model.Bones.Count];
            model.CopyAbsoluteBoneTransformsTo(transforms);

            foreach (ModelMesh mesh in model.Meshes)
            {
                foreach (BasicEffect effect in mesh.Effects)
                {

                    BetterBasic(effect);
                    effect.World = transforms[mesh.ParentBone.Index] * world;
                    effect.View = Camera.View;
                    effect.Projection = Camera.Projection;
                }
                mesh.Draw();
            }
        }

        public void BetterBasic(BasicEffect effect)
        {
            effect.LightingEnabled = true;
            effect.AmbientLightColor = new Vector3(0.05333332f, 0.9882354f, 0.1819608f);

            effect.DirectionalLight0.DiffuseColor = new Vector3(0, 0, 1);
            effect.DirectionalLight0.SpecularColor = effect.DirectionalLight0.DiffuseColor;
            effect.DirectionalLight0.Direction = new Vector3(0, -1, 0);
            effect.DirectionalLight0.Enabled = true;

            effect.DirectionalLight1.DiffuseColor = new Vector3(0, 0, 1);
            effect.DirectionalLight1.SpecularColor = effect.DirectionalLight1.DiffuseColor;
            effect.DirectionalLight1.Direction = Vector3.Normalize(new Vector3(-1, -1, -1));
            effect.DirectionalLight1.Enabled = true;

            effect.DirectionalLight2.DiffuseColor = new Vector3(0, 0, 1);
            effect.DirectionalLight2.SpecularColor = effect.DirectionalLight2.DiffuseColor;
            effect.DirectionalLight2.Direction = Vector3.Normalize(new Vector3(-1, -1, 1));
            effect.DirectionalLight2.Enabled = true;

        }
    }
}
